/**
 * elancom Corporation copy right 2012 - 2015  
 *   
 * $Header$
 * $Id$
 * $Author$
 * $Date$
 * $Revision$
 */
package com.elancom.framework.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

/**
 * @author elancom
 * @date 2012-7-20
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class A {
	/**
	 * Protect constructor since it is a static only class
	 */
	protected A() {
		// hide constructor
	}

	/**
	 * Asserts that a condition is true. If it isn't, an AssertionError, with the given message, is thrown.
	 * 
	 * @param condition
	 *            the condition to evaluate
	 * @param message
	 *            the assertion error message
	 */
	static public void trues(boolean condition, String message) {
		if (!condition) {
			failNotEquals(Boolean.valueOf(condition), Boolean.TRUE, message);
		}
	}

	/**
	 * Asserts that a condition is true. If it isn't, an AssertionError is thrown.
	 * 
	 * @param condition
	 *            the condition to evaluate
	 */
	static public void trues(boolean condition) {
		trues(condition, null);
	}

	/**
	 * Asserts that a condition is false. If it isn't, an AssertionError, with the given message, is thrown.
	 * 
	 * @param condition
	 *            the condition to evaluate
	 * @param message
	 *            the assertion error message
	 */
	static public void falses(boolean condition, String message) {
		if (condition) {
			failNotEquals(Boolean.valueOf(condition), Boolean.FALSE, message); // TESTNG-81
		}
	}

	/**
	 * Asserts that a condition is false. If it isn't, an AssertionError is thrown.
	 * 
	 * @param condition
	 *            the condition to evaluate
	 */
	static public void falses(boolean condition) {
		falses(condition, null);
	}

	/**
	 * Fails a test with the given message and wrapping the original exception.
	 * 
	 * @param message
	 *            the assertion error message
	 * @param realCause
	 *            the original exception
	 */
	static public void fail(String message, Throwable realCause) {
		AssertionError ae = new AssertionError(message);
		ae.initCause(realCause);

		throw ae;
	}

	/**
	 * Fails a test with the given message.
	 * 
	 * @param message
	 *            the assertion error message
	 */
	static public void fail(String message) {
		throw new AssertionError(message);
	}

	/**
	 * Fails a test with no message.
	 */
	static public void fail() {
		fail(null);
	}

	/**
	 * Asserts that two objects are equal. If they are not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(Object actual, Object expected, String message) {
		if ((expected == null) && (actual == null)) {
			return;
		}
		if ((expected != null) && expected.equals(actual)) {
			return;
		}
		failNotEquals(actual, expected, message);
	}

	/**
	 * Asserts that two objects are equal. If they are not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(Object actual, Object expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two Strings are equal. If they are not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(String actual, String expected, String message) {
		eq((Object) actual, (Object) expected, message);
	}

	/**
	 * Asserts that two Strings are equal. If they are not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(String actual, String expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two doubles are equal concerning a delta. If they are not, an AssertionError, with the given message, is thrown. If the expected value is
	 * infinity then the delta value is ignored.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param delta
	 *            the absolute tolerate value value between the actual and expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(double actual, double expected, double delta, String message) {
		// handle infinity specially since subtracting to infinite values gives NaN and the
		// the following test fails
		if (Double.isInfinite(expected)) {
			if (!(expected == actual)) {
				failNotEquals(new Double(actual), new Double(expected), message);
			}
		} else if (!(Math.abs(expected - actual) <= delta)) { // Because comparison with NaN always returns false
			failNotEquals(new Double(actual), new Double(expected), message);
		}
	}

	/**
	 * Asserts that two doubles are equal concerning a delta. If they are not, an AssertionError is thrown. If the expected value is infinity then the delta
	 * value is ignored.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param delta
	 *            the absolute tolerate value value between the actual and expected value
	 */
	static public void eq(double actual, double expected, double delta) {
		eq(actual, expected, delta, null);
	}

	/**
	 * Asserts that two floats are equal concerning a delta. If they are not, an AssertionError, with the given message, is thrown. If the expected value is
	 * infinity then the delta value is ignored.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param delta
	 *            the absolute tolerate value value between the actual and expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(float actual, float expected, float delta, String message) {
		// handle infinity specially since subtracting to infinite values gives NaN and the
		// the following test fails
		if (Float.isInfinite(expected)) {
			if (!(expected == actual)) {
				failNotEquals(new Float(actual), new Float(expected), message);
			}
		} else if (!(Math.abs(expected - actual) <= delta)) {
			failNotEquals(new Float(actual), new Float(expected), message);
		}
	}

	/**
	 * Asserts that two floats are equal concerning a delta. If they are not, an AssertionError is thrown. If the expected value is infinity then the delta
	 * value is ignored.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param delta
	 *            the absolute tolerate value value between the actual and expected value
	 */
	static public void eq(float actual, float expected, float delta) {
		eq(actual, expected, delta, null);
	}

	/**
	 * Asserts that two longs are equal. If they are not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(long actual, long expected, String message) {
		eq(new Long(actual), new Long(expected), message);
	}

	/**
	 * Asserts that two longs are equal. If they are not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(long actual, long expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two booleans are equal. If they are not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(boolean actual, boolean expected, String message) {
		eq(Boolean.valueOf(actual), Boolean.valueOf(expected), message);
	}

	/**
	 * Asserts that two booleans are equal. If they are not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(boolean actual, boolean expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two bytes are equal. If they are not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(byte actual, byte expected, String message) {
		eq(new Byte(actual), new Byte(expected), message);
	}

	/**
	 * Asserts that two bytes are equal. If they are not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(byte actual, byte expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two chars are equal. If they are not, an AssertionFailedError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(char actual, char expected, String message) {
		eq(new Character(actual), new Character(expected), message);
	}

	/**
	 * Asserts that two chars are equal. If they are not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(char actual, char expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two shorts are equal. If they are not, an AssertionFailedError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(short actual, short expected, String message) {
		eq(new Short(actual), new Short(expected), message);
	}

	/**
	 * Asserts that two shorts are equal. If they are not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(short actual, short expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two ints are equal. If they are not, an AssertionFailedError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(int actual, int expected, String message) {
		eq(new Integer(actual), new Integer(expected), message);
	}

	/**
	 * Asserts that two ints are equal. If they are not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(int actual, int expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that an object isn't null. If it is, an AssertionError is thrown.
	 * 
	 * @param object
	 *            the assertion object
	 */
	static public void notNull(Object object) {
		notNull(object, null);
	}

	/**
	 * Asserts that an object isn't null. If it is, an AssertionFailedError, with the given message, is thrown.
	 * 
	 * @param object
	 *            the assertion object
	 * @param message
	 *            the assertion error message
	 */
	static public void notNull(Object object, String message) {
		trues(object != null, message);
	}

	/**
	 * Asserts that an object is null. If it is, an AssertionError, with the given message, is thrown.
	 * 
	 * @param object
	 *            the assertion object
	 */
	static public void nulls(Object object) {
		nulls(object, null);
	}

	/**
	 * Asserts that an object is null. If it is not, an AssertionFailedError, with the given message, is thrown.
	 * 
	 * @param object
	 *            the assertion object
	 * @param message
	 *            the assertion error message
	 */
	static public void nulls(Object object, String message) {
		trues(object == null, message);
	}

	/**
	 * Asserts that two objects refer to the same object. If they do not, an AssertionFailedError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void same(Object actual, Object expected, String message) {
		if (expected == actual) {
			return;
		}
		failNotSame(actual, expected, message);
	}

	/**
	 * Asserts that two objects refer to the same object. If they do not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void same(Object actual, Object expected) {
		same(actual, expected, null);
	}

	/**
	 * Asserts that two objects do not refer to the same objects. If they do, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void notSame(Object actual, Object expected, String message) {
		if (expected == actual) {
			failSame(actual, expected, message);
		}
	}

	/**
	 * Asserts that two objects do not refer to the same object. If they do, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void notSame(Object actual, Object expected) {
		notSame(actual, expected, null);
	}

	static private void failSame(Object actual, Object expected, String message) {
		String formatted = "";
		if (message != null) {
			formatted = message + " ";
		}
		fail(formatted + "expected not same with:<" + expected + "> but was same:<" + actual + ">");
	}

	static private void failNotSame(Object actual, Object expected, String message) {
		String formatted = "";
		if (message != null) {
			formatted = message + " ";
		}
		fail(formatted + "expected same with:<" + expected + "> but was:<" + actual + ">");
	}

	static private void failNotEquals(Object actual, Object expected, String message) {
		fail(format(actual, expected, message));
	}

	static String format(Object actual, Object expected, String message) {
		String formatted = "";
		if (null != message) {
			formatted = message + " ";
		}

		return formatted + "expected:<" + expected + "> but was:<" + actual + ">";
	}

	/**
	 * Asserts that two collections contain the same elements in the same order. If they do not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(Collection actual, Collection expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two collections contain the same elements in the same order. If they do not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(Collection actual, Collection expected, String message) {
		if (actual == expected)
			return;

		if ((actual == null && expected != null) || (actual != null && expected == null)) {
			if (message != null)
				fail(message);
			else
				fail("Arrays not equal: " + expected + " and " + actual);
		}

		eq(actual.size(), expected.size(), message + ": lists don't have the same size");

		Iterator actIt = actual.iterator();
		Iterator expIt = expected.iterator();
		int i = -1;
		while (actIt.hasNext() && expIt.hasNext()) {
			i++;
			Object e = expIt.next();
			Object a = actIt.next();
			String errorMessage = message == null ? "Lists differ at element [" + i + "]: " + e + " != " + a : message + ": Lists differ at element [" + i
					+ "]: " + e + " != " + a;

			eq(a, e, errorMessage);
		}
	}

	/**
	 * Asserts that two arrays contain the same elements in the same order. If they do not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(Object[] actual, Object[] expected, String message) {
		if (actual == expected)
			return;

		if ((actual == null && expected != null) || (actual != null && expected == null)) {
			if (message != null)
				fail(message);
			else
				fail("Arrays not equal: " + expected + " and " + actual);
		}
		eq(Arrays.asList(actual), Arrays.asList(expected), message);
	}

	/**
	 * Asserts that two arrays contain the same elements in no particular order. If they do not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eqNoOrder(Object[] actual, Object[] expected, String message) {
		if (actual == expected)
			return;

		if ((actual == null && expected != null) || (actual != null && expected == null)) {
			failAssertNoEqual(actual, expected, "Arrays not equal: " + expected + " and " + actual, message);
		}

		if (actual.length != expected.length) {
			failAssertNoEqual(actual, expected, "Arrays do not have the same size:" + actual.length + " != " + expected.length, message);
		}

		List actualCollection = new ArrayList();
		for (Object a : actual) {
			actualCollection.add(a);
		}
		for (Object o : expected) {
			actualCollection.remove(o);
		}
		if (actualCollection.size() != 0) {
			failAssertNoEqual(actual, expected, "Arrays not equal: " + expected + " and " + actual, message);
		}
	}

	private static void failAssertNoEqual(Object[] actual, Object[] expected, String message, String defaultMessage) {
		if (message != null)
			fail(message);
		else
			fail(defaultMessage);
	}

	/**
	 * Asserts that two arrays contain the same elements in the same order. If they do not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(Object[] actual, Object[] expected) {
		eq(actual, expected, null);
	}

	/**
	 * Asserts that two arrays contain the same elements in no particular order. If they do not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eqNoOrder(Object[] actual, Object[] expected) {
		eqNoOrder(actual, expected, null);
	}

	/**
	 * Asserts that two arrays contain the same elements in the same order. If they do not, an AssertionError is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 */
	static public void eq(final byte[] actual, final byte[] expected) {
		eq(actual, expected, "");
	}

	/**
	 * Asserts that two arrays contain the same elements in the same order. If they do not, an AssertionError, with the given message, is thrown.
	 * 
	 * @param actual
	 *            the actual value
	 * @param expected
	 *            the expected value
	 * @param message
	 *            the assertion error message
	 */
	static public void eq(final byte[] actual, final byte[] expected, final String message) {
		if (expected == actual) {
			return;
		}
		if (null == expected) {
			fail("expected a null array, but not null found. " + message);
		}
		if (null == actual) {
			fail("expected not null array, but null found. " + message);
		}

		eq(actual.length, expected.length, "arrays don't have the same size. " + message);

		for (int i = 0; i < expected.length; i++) {
			if (expected[i] != actual[i]) {
				fail("arrays differ firstly at element [" + i + "]; " + "expected value is <" + expected[i] + "> but was <" + actual[i] + ">. " + message);
			}
		}
	}
}
